package com.laiketui.order.service.pay.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.laiketui.common.mapper.UserMapper;
import com.laiketui.core.cache.RedisUtil;
import com.laiketui.core.exception.LaiKeAPIException;
import com.laiketui.core.utils.help.SpringHelper;
import com.laiketui.domain.lktconst.ErrorCode;
import com.laiketui.domain.user.User;
import com.laiketui.order.api.dto.pay.BalanceRecordDTO;
import com.laiketui.order.api.dto.pay.UserBalanceDTO;
import com.laiketui.order.api.enums.*;
import com.laiketui.order.api.params.pay.BalancePayParams;
import com.laiketui.order.api.params.pay.BalanceRecordParams;
import com.laiketui.order.common.RedissonLock;
import com.laiketui.order.domain.BalanceRecord;
import com.laiketui.order.domain.Order;
import com.laiketui.order.domain.OrderDetail;
import com.laiketui.order.domain.OrderParent;
import com.laiketui.order.mapstruct.BalanceRecordMapstructMapper;
import com.laiketui.order.mapstruct.UserMapstructMapper;
import com.laiketui.order.service.*;
import com.laiketui.order.service.pay.BalancePayService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class BalancePayServiceImpl implements BalancePayService {


    @Autowired
    private OrderParentService orderParentService;

    @Autowired
    RedissonLock redissonLock;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private BalanceRecordService balanceRecordService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderParentMessageService orderParentMessageService;


    @Override
    public String pay(BalancePayParams balancePayParams, String userId, Integer storeId) {
        OrderParent orderParent = getOrderParent(balancePayParams.getOrderParentNo());
        if (!OrderParentStatusEnum.WAIT_PAY.getCode().equals(orderParent.getStatus())) {
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DDBZDFKZT, "订单不是待支付状态", "pay");
        }
        BalancePayServiceImpl balancePayService = SpringHelper.getBeanInfo(BalancePayServiceImpl.class);
        String lockKey = "balance_pay_" + userId;
        try {
            RLock lock = redissonLock.lock(lockKey);
            return balancePayService.beginPay(userId, storeId, balancePayParams, orderParent);
        } finally {
            redissonLock.unlock(lockKey);
        }
    }

    @Override
    public UserBalanceDTO getUserInfo(User user) {
        User userDetail = getUser(user.getUser_id(), user.getStore_id());
        return UserMapstructMapper.INSTANCE.toDTO(userDetail);
    }

    @Override
    public IPage<BalanceRecordDTO> getBalanceRecords(User user, BalanceRecordParams balanceRecordParams ){
        Integer pageNum=balanceRecordParams.getPageNum();
        Integer pageSize=balanceRecordParams.getPageSize();
        if(Objects.isNull(pageNum)){
            pageNum=1;
        }
        if(Objects.isNull(pageSize)){
            pageSize=10;
        }
        Page<BalanceRecordDTO> balanceRecordDTOPage = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<BalanceRecord> wrapper=new LambdaQueryWrapper<BalanceRecord>();
        wrapper.eq(BalanceRecord::getUserId, user.getUser_id());
        if(Objects.nonNull(balanceRecordParams.getStartTime())){
            wrapper.ge(BalanceRecord::getCreatTime, balanceRecordParams.getStartTime());
        }
        if(Objects.nonNull(balanceRecordParams.getEndTime())){
            wrapper.le(BalanceRecord::getCreatTime, balanceRecordParams.getEndTime());
        }
        if(Objects.nonNull(balanceRecordParams.getMessageType())){
            wrapper.eq(BalanceRecord::getRecordType, balanceRecordParams.getMessageType());
        }
        if(StringUtils.isNotBlank(balanceRecordParams.getOrderParentNo())){
            wrapper.like(BalanceRecord::getOrderParentNo, balanceRecordParams.getOrderParentNo());
        }
        wrapper.orderByDesc(BalanceRecord::getId);
        IPage<BalanceRecord> page = balanceRecordService.page(new Page<>(pageNum, pageSize), wrapper);
        if(page.getTotal()<1L){
            return balanceRecordDTOPage;
        }
        balanceRecordDTOPage.setRecords(BalanceRecordMapstructMapper.INSTANCE.toDTOs(page.getRecords()));
        balanceRecordDTOPage.setTotal(page.getTotal());
        return balanceRecordDTOPage;
    }

    private OrderParent getOrderParent(String orderParentNo) {
        LambdaQueryWrapper<OrderParent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderParent::getOrderParentNo, orderParentNo);
        return orderParentService.getOne(wrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    public String beginPay(String userId, Integer storeId, BalancePayParams balancePayParams, OrderParent orderParent) {
        orderParent = getOrderParent(balancePayParams.getOrderParentNo());
        if (!OrderParentStatusEnum.WAIT_PAY.getCode().equals(orderParent.getStatus())) {
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_DDBZDFKZT, "订单不是待支付状态", "pay");
        }
        User user = getUser(userId, storeId);
        Long deductionAmount = 0L;
        if(!balancePayParams.isNotUseAmount()){
            long userHadMoney = Objects.nonNull(user.getBalance()) ? user.getBalance() : 0L;
            if (userHadMoney > (orderParent.getPayPrice())) {
                //如果余额足够支付
                deductionAmount = orderParent.getPayPrice();
                //余额支付
                orderParent.setPayType(PayTypeEnum.BALANCE_PAY.getCode());
            } else {
                //如果不够支付
                deductionAmount = Objects.nonNull(user.getBalance()) ? user.getBalance() : 0L;
                if(deductionAmount.equals(0L)){
                    //银行转账
                    orderParent.setPayType(PayTypeEnum.OFFLINE_PAY.getCode());
                }else{
                    //银行转账+余额支付
                    orderParent.setPayType(PayTypeEnum.OFFLINE_BALANCE_PAY.getCode());
                }
            }
        }
        if(!deductionAmount.equals(orderParent.getPayPrice()) && StringUtils.isBlank(balancePayParams.getOfflinePayImg())){
            //如果不是全部用余额支付需要校验上传凭证
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "请上传凭证", "placeOrder");
        }
        if (deductionAmount > 0) {
            int i = userMapper.freezeMoney(deductionAmount, storeId, userId);
            if (i <= 0) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "支付失败", "placeOrder");
            }
            balanceRecordService.addFreezeRecord(deductionAmount, storeId, userId, orderParent.getOrderParentNo(), BalanceRecordTypeEnum.FREEZE_AMOUNT.getCode(), userId);
        }
        OrderParent updateOrderParent = new OrderParent();
        updateOrderParent.setStatus(OrderParentStatusEnum.WAIT_CHECK.getCode());
        if(deductionAmount.equals(orderParent.getPayPrice())){
            //全部用余额支付就是已完成
            updateOrderParent.setStatus(OrderParentStatusEnum.WAIT_SEND.getCode());
        }
        updateOrderParent.setDeductionAmount(deductionAmount);
        Long offlinePayAmount=orderParent.getPayPrice() - deductionAmount;
        updateOrderParent.setOfflinePayAmount(offlinePayAmount<0L?0L:offlinePayAmount);
        updateOrderParent.setOfflinePayStatus(OrderOfflinePayStatusEnum.PAYED.getCode());
        updateOrderParent.setStatus(OrderParentStatusEnum.WAIT_CHECK.getCode());
        if (Objects.nonNull(balancePayParams.getOfflinePayTime())) {
            updateOrderParent.setOfflinePayTime(balancePayParams.getOfflinePayTime());
        }
        if (StringUtils.isNotBlank(balancePayParams.getOfflinePayBank())) {
            updateOrderParent.setOfflinePayBank(balancePayParams.getOfflinePayBank());
        }
        if (StringUtils.isNotBlank(balancePayParams.getOfflinePayImg())) {
            updateOrderParent.setOfflinePayImg(balancePayParams.getOfflinePayImg());
            updateOrderParent.setOfflinePayStatus(OrderOfflinePayStatusEnum.PAYED.getCode());
        }
        updateOrderParent.setId(orderParent.getId());
        updateOrderParent.setUpdateBy(userId);
        if(Objects.nonNull(balancePayParams.getOfflinePayType())){
            updateOrderParent.setOfflinePayType(balancePayParams.getOfflinePayType());
        }else{
            updateOrderParent.setOfflinePayType(OfflinePayTypeEnum.BANK.getCode());
        }
        updateOrderParent.setPayType(orderParent.getPayType());
        Date now = new Date();
        updateOrderParent.setUpdateTime(now);
        updateOrderParent.setPrepaymentTime(now);
        if(deductionAmount >= orderParent.getPayPrice()) {
            //如果是全部使用余额支付要更新子单已经订单子项
            updateOrderAndDetail(userId, now,orderParent,orderParent.getPayType());
            updateOrderParent.setStatus(OrderParentStatusEnum.WAIT_SEND.getCode());
            orderParentMessageService.addOrderParentMessageAndPhoto(userId,storeId,OrderParentMessageType.ORDER_PAY_SUCCESS.getCode(), orderParent.getOrderParentNo(), OrderParentStatusEnum.WAIT_SEND.getCode(),"支付成功 支付方式: 电子钱包余额",balancePayParams.getOfflinePayImg());
        }else {
            String messageContext;
            if(deductionAmount.equals(0L)){
                messageContext="支付成功 支付方式: 银行转账";
            }else{
                messageContext="支付成功 支付方式: 电子钱包余额+银行转账";
            }
            orderParentMessageService.addOrderParentMessageAndPhoto(userId,storeId,OrderParentMessageType.ORDER_PAY_SUCCESS.getCode(), orderParent.getOrderParentNo(), OrderParentStatusEnum.WAIT_CHECK.getCode(),messageContext,balancePayParams.getOfflinePayImg());
        }
        //更新母订单
        orderParentService.updateById(updateOrderParent);


        return orderParent.getOrderParentNo();
    }

    public void updateOrderAndDetail(String userId, Date now,OrderParent orderParent,Integer payType) {
        Order order = new Order();
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getOrderParentNo, orderParent.getOrderParentNo());
        order.setUpdateBy(userId);
        order.setUpdateTime(now);
        order.setStatus(OrderStatusEnum.WAIT_CHECK.getCode());
        order.setPayType(payType);
        orderService.update(order, wrapper);

        OrderDetail detail = new OrderDetail();
        LambdaQueryWrapper<OrderDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.eq(OrderDetail::getOrderParentNo, orderParent.getOrderParentNo());
        detail.setUpdateBy(userId);
        detail.setUpdateTime(now);
        detail.setStatus(OrderDetailEnum.WAIT_CHECK.getCode());
        orderDetailService.update(detail, detailWrapper);
    }

    public User getUser(String userId, Integer storeId) {
        User selectUser = new User();
        selectUser.setStore_id(storeId);
        selectUser.setUser_id(userId);
        return userMapper.selectOne(selectUser);
    }
}
